/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.john;

/**
 *
 * @author John
 */
/**
 * @author Jhon Avila
 */
import com.john.utils.CreatePertFile;
import com.john.utils.LoadFile;
import com.john.utils.LongestPath;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;

public class Pert {

    public ArrayList<Edge> critical;
    private List<Edge> edges;
    private String name;
    private HashMap<String, Task> TASK_MAP;
    /*
     * Adyacency Matrix
     */
    private Integer adMtx[][];

    public Pert() {
        TASK_MAP = new HashMap<>();
        edges = new ArrayList<>();


    }

    public void calcCPath(int num_nods, Pert pert) {
        Integer path[][] = new Integer[pert.getAdMtx().length][pert.getAdMtx().length];
        Integer path2[][] = pert.getAdMtx();
        Edge p[][] = new Edge[path.length][path.length];
        for (int i = 0; i < pert.getAdMtx().length; i++) {
            for (int j = 0; j < pert.getAdMtx().length; j++) {
                Edge ed = pert.pathExist(i, j, pert);
                if (ed != null) {
                    p[i][j] = ed;
                    path[i][j] = ed.getSource().getDuration();
                }
            }
        }
        //Se the diagonal on Ceros
        for (int i = 0; i < p.length; i++) {
            path[i][i] = 0;
        }
        //FLoyMarshall implementation... i don't know why i even consider this...
        for (int i = 0; i < p.length; i++) {
            for (int j = 0; j < p.length; j++) {
                if (p[i][j] != null) {
                    for (int k = 0; k < p.length; k++) {
                        if (i != k) {
                            try {
                                if (path[j][k] > path[j][i] + path[i][k]) {
                                    p[j][k] = p[j][i];
                                    path[j][k] = path[j][i] + path[i][k];
                                    System.out.println("path[" + j + "][" + k + "]=" + path[j][k]);
                                }
                            } catch (NullPointerException e) {
                            }

                        }
                    }
                }
            }
        }

        System.out.println("End MAtrix");

        for (int i = 0; i < p.length; i++) {

            for (int j = 0; j < p.length; j++) {
                if (p[i][j] != null) {
                    System.out.println("p[i][j]= " + p[i][j].getSource().gettIdentifier() + " -> " + p[i][j].getDestination().gettIdentifier());
                }
            }

        }
        System.out.println("PRINT PATH");
        for (int i = 0; i < path.length; i++) {

            for (int j = 0; j < path.length; j++) {
                System.out.format("%s ", path[i][j]);

            }
            System.out.println("");
        }
        //pert.getPaths(pert.getTASK_MAP().get("start"));
        //  pert.getPaths(pert.getTASK_MAP().get("start"), 0);
    }

    public int getPaths(Task task, int n) {


        if (task.getOutgoing().isEmpty()) {
            return 0;
        } else {
            System.out.println("" + task.gettIdentifier());
            //getPaths(task.getOutgoing(), 1);
            return n;
        }


    }

    public List<Task> getTaskes(String REGS[]) {
        // Task task = new Task(null, null, REGS[0], Integer.parseInt(REGS[1]));
        for (int i = 2; i < REGS.length; i++) {
            String string1 = REGS[i];
            Edge ed = new Edge();
        }
        return null;
    }

    public int getVertexCount(List a) {
        return a.size();
    }
//====================================Main

    public static void main(String arg[]) throws Exception {
        Pert pert = new Pert();
        pert.setName("Chart1");
        JOptionPane.showMessageDialog(null, "Welcome to PERT GEN v0.1, it is Assumed that the file format is correct \n and has no cycles File format is the following\n TASKn, Durationm, TaskPred0 ,TaskPred1 , ...,TaskPredm");

        LoadFile load = new LoadFile();
        List<String> REGS;
        try {
            File fileToRead = new File("");
           
            System.out.println(""+fileToRead.getAbsolutePath());
            if(arg.length>0){
                fileToRead=new File(arg[0]);
            
          
            //REGS = load.loadPertFromFile("D:\\John\\pertExample.txt");
           
            REGS = load.loadPertFromFile(arg[0]);
            int mtxSize = pert.getVertexCount(REGS);
            pert.setAdMtx(new Integer[mtxSize][mtxSize]);
            int idx = 0;

            // Parse File Structure
            for (Iterator<String> it = REGS.iterator(); it.hasNext();) {
                String string = it.next();
                String STR_TASK[] = string.split(LoadFile.FILE_SPLIT);
                Task taskParsing = new Task(pert, STR_TASK[0].toLowerCase().trim(), Integer.parseInt(STR_TASK[1].trim()));
                if (idx == 0) {
                    taskParsing.setTaskId(String.valueOf(idx));
                    idx = 1;
                } else {
                    taskParsing.setTaskId(String.valueOf(idx++));
                }
                taskParsing.settIdentifier(STR_TASK[0].toLowerCase().trim());
                pert.getTASK_MAP().put(STR_TASK[0].toLowerCase().trim(), taskParsing);


                // Get predecessors
                if (STR_TASK.length > 2) {
                    for (int i = 2; i < STR_TASK.length; i++) {
                        String dependencies = STR_TASK[i];
                        Task t_pred = pert.getTASK_MAP().get(dependencies.toLowerCase().trim());
                        Task task = pert.getTASK_MAP().get(STR_TASK[0].toLowerCase().trim());
                        Edge e = null;
                        if (task != null) {
                            e = new Edge();
                            e.setSource(t_pred);
                            e.setDestination(task);
                            e.setWithin(pert);
                            t_pred.getOutgoing().add(e);
                            pert.getEdges().add(e);
                            pert.getAdMtx()[Integer.parseInt(t_pred.getTaskId())][Integer.parseInt(task.getTaskId())] = task.getDuration();
                        }
                    }
                }

            }

            System.out.println("" + pert.edges.size());
            // HEre i initialice the structure that the thirdparty class uses to 
            // calculate de longest PATH in the PERT CHART
            List<String> d = new ArrayList<>();
            System.out.println("" + pert.getTASK_MAP().size());
            d.add(pert.getTASK_MAP().size() + " " + pert.edges.size());
            for (Iterator<Edge> it = pert.edges.iterator(); it.hasNext();) {
                Edge e = it.next();
                System.out.println("< id=" + e.getSource().getTaskId() + ":" + e.getSource().gettIdentifier() + ":" + e.getSource().getDuration() + " , id=" + e.getDestination().getTaskId() + ":" + e.getDestination().gettIdentifier() + ":" + e.getDestination().getDuration() + "> ");
                d.add(e.getSource().getTaskId() + " " + e.getDestination().getTaskId() + " " + e.getDestination().getDuration());
            }
            LongestPath lon = new LongestPath(d);
            if (lon.findLongestPath(0, lon.getN() - 1, 1)) {
                System.out.println("Longest Path is " + lon + " and the distance is " + lon.getBestDistance());
            } else {
                System.out.println("No path from v0 to v" + (lon.getN() - 1));
            }


            //MY BEST SHOT WITH WARSHALL - FLOYD ALGORITHM
            // I MADE IT BUT I FAILED TO INTERPRET CORRECTLY THE RESULTS OF THE ADYACENCY MATRIX
           /* System.out.println(" Initial MAtrix");
             for (int i = 0; i < pert.adMtx.length; i++) {
             for (int j = 0; j < pert.adMtx.length; j++) {
             System.out.print(" " + (pert.adMtx[i][j]) + "  ");
             }
             System.out.println("");
             }

             System.out.println("CalPAth");
             pert.calcCPath(pert.adMtx.length - 1, pert);

             */
            System.out.println("CRIT_PATH");
            String crit[] = lon.toString().split(",");
            pert.setCritical(new ArrayList());
            for (int i = 0; i < crit.length; i++) {
                if (i + 1 < crit.length) {
                    String string = crit[i] + "," + crit[i + 1];
                    System.out.println("" + string);

                    for (ListIterator<Edge> it = pert.edges.listIterator(); it.hasNext();) {
                        Edge edge1 = it.next();
                        if (edge1.getSource().getTaskId().equals(string.split(",")[0]) && edge1.getDestination().getTaskId().equals(string.split(",")[1])) {
                            System.out.println("Critical ");
                            edge1.setIsCritical(true);
                            // pert.getCritical().add(edge1);
                        }

                    }
                }
            }

            for (ListIterator<Edge> it = pert.edges.listIterator(); it.hasNext();) {
                Edge edge1 = it.next();
                System.out.println("" + edge1.isIsCritical());

            }
            CreatePertFile cre = new CreatePertFile();
            cre.printDotFile(new ArrayList<>(pert.TASK_MAP.values()), pert, lon);
              }
            else {
            JOptionPane.showMessageDialog(null,"Please put the full path of the file to parse \n for example on command line:   java -jar SysModAssigment.jar D:\\\\John\\\\pertExample.txt ");
            }//pertExample.txt
        } catch (FileNotFoundException ex) {
            Logger.getLogger(Pert.class
                    .getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(Pert.class
                    .getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * to check if path exist beetween two nodes
     *
     * @param s
     * @param t
     * @param pert
     * @return
     */
    public Edge pathExist(int s, int t, Pert pert) {

        Edge path = null;
        for (Iterator<Edge> it = edges.iterator(); it.hasNext();) {
            Edge edge = it.next();
            int vs = Integer.parseInt(edge.getSource().getTaskId());
            int vt = Integer.parseInt(edge.getDestination().getTaskId());
            if (s == vs && t == vt) {
                System.out.println("PAth for s,t=" + s + "," + t);
                System.out.print(" s->" + edge.getSource().getTaskId());
                System.out.println(" t->" + edge.getDestination().getTaskId());
                return edge;
            }
        }


        return null;
    }

    //=================================GET-SET
    public Integer[][] getAdMtx() {
        return adMtx;
    }

    public void setAdMtx(Integer[][] adMtx) {
        this.adMtx = adMtx;
    }

    public ArrayList<Edge> getCritical() {
        return critical;
    }

    public void setCritical(ArrayList<Edge> critical) {
        this.critical = critical;
    }

    public List<Edge> getHas() {
        return edges;
    }

    public void setHas(List<Edge> has) {
        this.edges = has;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<Edge> getEdges() {
        return edges;
    }

    public void setEdges(List<Edge> edges) {
        this.edges = edges;
    }

    public HashMap<String, Task> getTASK_MAP() {
        return TASK_MAP;
    }

    public void setTASK_MAP(HashMap<String, Task> TASK_MAP) {
        this.TASK_MAP = TASK_MAP;
    }
}
